<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0px;
            padding: 0px;
        }
        .container {
            margin: 0 auto;
            width: 750px;
            height: 500px;
            border: 1px solid red;
            position: relative;
            background-image: url(./images/1.jpg);
            background-repeat: no-repeat;
            background-size: 750px 450px;
        }
        .clip { 
            width: 50px;
            height: 50px;
            position: absolute;
            background-image: url(./images/1.jpg);
            background-repeat: no-repeat;
            background-position: -100px -0px;
            background-size: 750px 450px;
            top: 0px;
            left: 0px;
            z-index: 99;
        }
        .black {
            width: 50px;
            height: 50px;
            background-color: black;
            position: absolute;
            top: 0px;
            left: 100px;
        }
        .swiper {
            width: 50px;
            height: 50px;
            background-color: brown;
            line-height: 50px;
            text-align: center;
            position: absolute;
            top: 450px;
            border-radius: 10px;
        }
        .refresh {
            width: 50px;
            height: 50px;
            position: absolute;
            background-image: url(./images/refresh.png);
            background-size: 50px 50px;
            top: 450px;
            right: 0px;
            border-radius: 10px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="clip">
        </div>
        <div class="black">
        </div>
        <div class="swiper">
            滑动
        </div>
        <div class="refresh">
        </div>
    </div>
    <script>
        function SlidingValidation(containerEle,imgArr,cb){//定义一个SlidingValidation 类 （滑动验证）   需要传入三个参数，一个为容器盒子，一个图片路径数组，以及验证成功需要执行的回调函数
            this.containerEle = containerEle ;  //让容器元素成为属性
            this.imgArr = imgArr ;              //图片路径数组成为属性
            this.cb = cb ;                      //回调函数成为他的属性
            this.blackEle = this.containerEle.querySelector(".black");  //获取容器中className为black的元素
            this.swiperEle = this.containerEle.querySelector(".swiper");//获取容器中className为swiper的元素
            this.clipEle = this.containerEle.querySelector(".clip");    //获取容器中className为clip的元素
            this.refreshEle = this.containerEle.querySelector(".refresh");//获取容器中className为refresh的元素
            this.resetEle();                        //执行resetEle();
            this.refresh();                         //执行refresh();
            this.sWiper();                         //执行sWiper();    
        }
        SlidingValidation.prototype.getClip = function (ele1,ele2){//在原型上封装一个getClip();方法，传入两个元素，计算裁剪区域的起始坐标
            let w1 = parseInt(getStyle(ele1,"width"));      //第一个元素为容器元素，第二个元素为裁剪的元素，分别获取他们的宽高
            let h1 = parseInt(getStyle(ele1,"height"));
            let w2 = parseInt(getStyle(ele2,"width"));
            let h2 = parseInt(getStyle(ele2,"height"));
            let ranX = getRand( w1 - w2 , w2 ) ;        //在水平方向上，只需要考虑裁剪的  起始坐标 由   裁剪元素的宽   到   容器盒子的宽-去裁剪元素的宽
            let ranY = getRand( h1 - h2 * 2 , 0 ) ;    //在垂直方向上，因为有滑动条，起始坐标  由  0  到    容器盒子的宽  -  裁剪元素的高  -  滑动条的 高
            return [ranX,ranY] ;            //然后一个数组， 数组第一个值   为   起始位置的横坐标 ，第二个值  为   起始位置的纵坐标
        }
        SlidingValidation.prototype.resetEle = function (){//在原型上定义一个resetEle()方法，当验证失败的时候重置元素的样式
            let arr = this.getClip(this.containerEle,this.blackEle);        //获取getClip();中随机到的起始位置的横纵坐标
            let str = this.imgArr[getRand(this.imgArr.length - 1 ,0)];  //在图片数组中获取一个图片的路径
    
            this.containerEle.style.backgroundImage = `url(${str})` ;       //将图片路径设置为容器盒子的背景图
            this.clipEle.style.backgroundImage = `url(${str})` ;            //将图片路径设置为裁剪的的背景图

            this.blackEle.style.top = arr[1] +"px";             //遮盖元素的起始纵坐标
            this.blackEle.style.left = arr[0] +"px";            //遮盖元素的起始横坐标

            this.clipEle.style.top = arr[1] +"px";              //裁剪元素的起始纵坐标  ，保证遮盖的地方与裁剪的水平位置一样大小一样
            this.clipEle.style.backgroundPosition = `-${arr[0]}px -${arr[1]}px` ;   //裁剪元素截取背景图所在的位置

            this.swiperEle.style.left = "0px" ;         //滑动条起始位置
            this.clipEle.style.left = "0px" ;           //裁剪元素起始位置
        }
        SlidingValidation.prototype.refresh = function (){ //定义一个refresh ，点击的时候刷新图片以及位置方法
            this.refreshEle.onclick = ()=>{     
                this.resetEle();
            }
        }
        SlidingValidation.prototype.sWiper = function (){//定义一个sWiper滑动条拖拽的方法
            const _that = this ;                //声明一个_that接收this指向
            _that.swiperEle.onmousedown = function (){      //拖拽滑动条
                let x = containerEle.offsetLeft ;           //获取容器元素距离浏览器的水平距离
                document.onmousemove = function (event){    //获取鼠标移动事件
                    let e = event || window.event ;         //事件兼容性
                    let mouseX = e.clientX ;                //获取鼠标的水平位置
                    _that.swiperEle.style.left = mouseX - x + "px" ; //滑动条的横坐标为鼠标的水平位置减去容器距离浏览器的水平距离
                    _that.clipEle.style.left = mouseX - x + "px" ;    //裁剪元素和滑动条同步滑动  所以裁剪元素的横坐标也为鼠标的水平位置减去容器距离浏览器的水平距离
                }
                document.onmouseup = ()=>{                  //松开鼠标
                    document.onmousemove = '' ;              //释放鼠标移动事件
                    let ww = parseInt(_that.blackEle.style.left) ;      //获取遮盖元素的水平位置 
                    let xx = parseInt(_that.clipEle.style.left) ;       //获取此时裁剪元素的水平位置

                    if( Math.abs( ww - xx ) <= 2 ){             //遮盖元素的水平位置与裁剪元素的水平位置的距离之差是否小于等于2像素
                        _that.cb() ;                            //是的话执行回调函数cb
                    } else {                    //不是
                        _that.resetEle();       //容器内元素位置重置，背景重置
                        
                    }
                    document.onmouseup = '' ;       //释放鼠标抬起事件
                }
            }
        }
        
        let imgArr = ["images/1.jpg","images/2.jpg","images/3.jpg","images/4.jpg","images/5.jpg"] ;
        let containerEle = document.querySelector(".container");
        let url = "http://www.baidu.com" ;
        new SlidingValidation(containerEle,imgArr,function(){
            alert("验证成功！");
        });

        function getRand(max,min){                      //定义一个获取随机数方法
            return parseInt( Math.random() * ( max - min  + 1 ) + min ) ;
        }
        function getStyle(ele,styleName){               //定义一个元素的属性获取方法，做元素属性兼容性
            if(window.getComputedStyle){
                return getComputedStyle(ele,'null')[styleName] ; 
            } else {
                return ele.currentStyle[styleName] ;
            }
        }
    </script>
</body>
</html>